package com.chiyoyo.rabbitmq.framework.init;

import com.chiyoyo.rabbitmq.framework.annotation.RabbitMq;
import com.chiyoyo.rabbitmq.framework.dto.BaseRabbitMqConstant;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @author chil
 * 根据常量类创建 RabbitMq
 */
public class InitRabbitMqAnno {

    /**
     * 根据常量类创建 RabbitMq 对象
     *
     * @param rabbitMq RabbitMq 对象
     * @return RabbitMq 对象
     */
    public static <T extends Enum<T> & BaseRabbitMqConstant> RabbitMq createRabbitMqFromConstantsClass(RabbitMq rabbitMq) {
        Class<? extends BaseRabbitMqConstant> constantsClass = rabbitMq.constantsClass();
        String constantName = rabbitMq.constantName();

        BaseRabbitMqConstant rabbitMqConstant = Enum.valueOf((Class<T>) constantsClass.asSubclass(Enum.class), constantName);
        // 提取原始注解的属性
        Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(rabbitMq);

        // 更新属性值
        updateAttribute(attributes, "queue", rabbitMqConstant.getQueue());
        updateAttribute(attributes, "exchange", rabbitMqConstant.getExchange());
        updateAttribute(attributes, "routingKey", rabbitMqConstant.getRoutingKey());
        updateAttribute(attributes, "exchangeType", rabbitMqConstant.getExchangeType());

        return (RabbitMq) Proxy.newProxyInstance(
                RabbitMq.class.getClassLoader(),
                new Class<?>[]{RabbitMq.class},
                new AnnotationInvocationHandler(attributes)
        );
    }

    /**
     * 更新属性值，如果新值不为null则替换
     *
     * @param attributes 属性映射
     * @param key        属性键
     * @param newValue   新属性值
     */
    private static void updateAttribute(Map<String, Object> attributes, String key, String newValue) {
        if (newValue != null && !newValue.isEmpty()) {
            attributes.put(key, newValue);
        }
    }

    /**
     * 根据常量类创建 RabbitMq 对象
     */
    private static class AnnotationInvocationHandler implements InvocationHandler {
        private final Map<String, Object> attributes;

        AnnotationInvocationHandler(Map<String, Object> attributes) {
            this.attributes = attributes;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return attributes.get(method.getName());
        }
    }
}
